//! Abstract Syntax Tree (AST) for the Cangjie language
//!
//! This module defines all the AST node types that represent the structure
//! of Cangjie source code after parsing.

use std::fmt;

/// File represents a complete Cangjie source file
#[derive(Debug, Clone)]
pub struct File {
    pub package: Option<PackageDecl>,
    pub imports: Vec<ImportDecl>,
    pub declarations: Vec<Decl>,
}

/// Package declaration
#[derive(Debug, Clone)]
pub struct PackageDecl {
    pub name: String,
    pub path: Vec<String>,
}

/// Import declaration
#[derive(Debug, Clone)]
pub struct ImportDecl {
    pub path: Vec<String>,
    pub alias: Option<String>,
}

/// Top-level declarations
#[derive(Debug, Clone)]
pub enum Decl {
    Class(ClassDecl),
    Interface(InterfaceDecl),
    Struct(StructDecl),
    Enum(EnumDecl),
    Function(FunctionDecl),
    Variable(VariableDecl),
    TypeAlias(TypeAliasDecl),
}

/// Class declaration
#[derive(Debug, Clone)]
pub struct ClassDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub members: Vec<Decl>,
    pub superclass: Option<Identifier>,
    pub interfaces: Vec<Identifier>,
}

/// Interface declaration
#[derive(Debug, Clone)]
pub struct InterfaceDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub members: Vec<Decl>,
    pub superinterfaces: Vec<Identifier>,
}

/// Struct declaration
#[derive(Debug, Clone)]
pub struct StructDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub members: Vec<VariableDecl>,
}

/// Enum declaration
#[derive(Debug, Clone)]
pub struct EnumDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub members: Vec<EnumMember>,
}

/// Enum member
#[derive(Debug, Clone)]
pub struct EnumMember {
    pub name: String,
    pub value: Option<Expr>,
}

/// Function declaration
#[derive(Debug, Clone)]
pub struct FunctionDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub parameters: Vec<Parameter>,
    pub return_type: Option<Type>,
    pub body: Option<BlockStmt>,
}

/// Function parameter
#[derive(Debug, Clone)]
pub struct Parameter {
    pub name: String,
    pub type_annotation: Option<Type>,
    pub default_value: Option<Expr>,
}

/// Variable declaration
#[derive(Debug, Clone)]
pub struct VariableDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub type_annotation: Option<Type>,
    pub initializer: Option<Expr>,
    pub is_mutable: bool,
}

/// Type alias declaration
#[derive(Debug, Clone)]
pub struct TypeAliasDecl {
    pub name: String,
    pub modifiers: Vec<String>,
    pub type_annotation: Type,
}

/// Types
#[derive(Debug, Clone)]
pub enum Type {
    Named(NamedType),
    Function(FunctionType),
    Array(ArrayType),
    Optional(OptionalType),
    Tuple(TupleType),
}

/// Named type (e.g., Int32, String, CustomType)
#[derive(Debug, Clone)]
pub struct NamedType {
    pub name: String,
}

/// Function type
#[derive(Debug, Clone)]
pub struct FunctionType {
    pub parameters: Vec<Type>,
    pub return_type: Box<Type>,
}

/// Array type
#[derive(Debug, Clone)]
pub struct ArrayType {
    pub element_type: Box<Type>,
}

/// Optional type
#[derive(Debug, Clone)]
pub struct OptionalType {
    pub base_type: Box<Type>,
}

/// Tuple type
#[derive(Debug, Clone)]
pub struct TupleType {
    pub elements: Vec<Type>,
}

/// Expressions
#[derive(Debug, Clone)]
pub enum Expr {
    Identifier(Identifier),
    Literal(Literal),
    Binary(BinaryExpr),
    Unary(UnaryExpr),
    Call(CallExpr),
    Member(MemberExpr),
    Index(IndexExpr),
    Array(ArrayExpr),
    Object(ObjectExpr),
    This(ThisExpr),
    Super(SuperExpr),
    Assignment(AssignmentExpr),
}

/// Identifier expression
#[derive(Debug, Clone)]
pub struct Identifier {
    pub name: String,
}

/// Literal expressions
#[derive(Debug, Clone)]
pub enum Literal {
    Integer(IntegerLiteral),
    Float(FloatLiteral),
    String(StringLiteral),
    Boolean(BooleanLiteral),
    Null(NullLiteral),
}

/// Integer literal
#[derive(Debug, Clone)]
pub struct IntegerLiteral {
    pub value: String,
}

/// Float literal
#[derive(Debug, Clone)]
pub struct FloatLiteral {
    pub value: String,
}

/// String literal
#[derive(Debug, Clone)]
pub struct StringLiteral {
    pub value: String,
}

/// Boolean literal
#[derive(Debug, Clone)]
pub struct BooleanLiteral {
    pub value: bool,
}

/// Null literal
#[derive(Debug, Clone)]
pub struct NullLiteral {}

/// Binary expression (e.g., a + b, x > y)
#[derive(Debug, Clone)]
pub struct BinaryExpr {
    pub left: Box<Expr>,
    pub operator: String,
    pub right: Box<Expr>,
}

/// Unary expression (e.g., -x, !flag)
#[derive(Debug, Clone)]
pub struct UnaryExpr {
    pub operator: String,
    pub operand: Box<Expr>,
}

/// Function call expression
#[derive(Debug, Clone)]
pub struct CallExpr {
    pub callee: Box<Expr>,
    pub arguments: Vec<Expr>,
}

/// Member access expression (e.g., obj.property)
#[derive(Debug, Clone)]
pub struct MemberExpr {
    pub object: Box<Expr>,
    pub property: Identifier,
}

/// Index access expression (e.g., arr[index])
#[derive(Debug, Clone)]
pub struct IndexExpr {
    pub array: Box<Expr>,
    pub index: Box<Expr>,
}

/// Array literal expression
#[derive(Debug, Clone)]
pub struct ArrayExpr {
    pub elements: Vec<Expr>,
}

/// Object literal expression
#[derive(Debug, Clone)]
pub struct ObjectExpr {
    pub properties: Vec<Property>,
}

/// Object property
#[derive(Debug, Clone)]
pub struct Property {
    pub name: String,
    pub value: Expr,
}

/// This expression
#[derive(Debug, Clone)]
pub struct ThisExpr {}

/// Super expression
#[derive(Debug, Clone)]
pub struct SuperExpr {}

/// Assignment expression
#[derive(Debug, Clone)]
pub struct AssignmentExpr {
    pub left: Box<Expr>,
    pub operator: String,
    pub right: Box<Expr>,
}

/// Statements
#[derive(Debug, Clone)]
pub enum Stmt {
    Expression(ExpressionStmt),
    Block(BlockStmt),
    If(IfStmt),
    While(WhileStmt),
    For(ForStmt),
    Return(ReturnStmt),
    Break(BreakStmt),
    Continue(ContinueStmt),
    Try(TryStmt),
    Variable(VariableStmt),
    Function(FunctionStmt),
}

/// Expression statement
#[derive(Debug, Clone)]
pub struct ExpressionStmt {
    pub expression: Expr,
}

/// Block statement
#[derive(Debug, Clone)]
pub struct BlockStmt {
    pub statements: Vec<Stmt>,
}

/// If statement
#[derive(Debug, Clone)]
pub struct IfStmt {
    pub condition: Expr,
    pub then_branch: BlockStmt,
    pub else_branch: Option<BlockStmt>,
}

/// While statement
#[derive(Debug, Clone)]
pub struct WhileStmt {
    pub condition: Expr,
    pub body: BlockStmt,
}

/// For statement
#[derive(Debug, Clone)]
pub struct ForStmt {
    pub initializer: Option<Box<Stmt>>,
    pub condition: Option<Expr>,
    pub increment: Option<Box<Stmt>>,
    pub body: BlockStmt,
}

/// Return statement
#[derive(Debug, Clone)]
pub struct ReturnStmt {
    pub value: Option<Expr>,
}

/// Break statement
#[derive(Debug, Clone)]
pub struct BreakStmt {}

/// Continue statement
#[derive(Debug, Clone)]
pub struct ContinueStmt {}

/// Try statement
#[derive(Debug, Clone)]
pub struct TryStmt {
    pub block: BlockStmt,
    pub catches: Vec<CatchClause>,
    pub finally_block: Option<BlockStmt>,
}

/// Catch clause
#[derive(Debug, Clone)]
pub struct CatchClause {
    pub parameter: Parameter,
    pub block: BlockStmt,
}

/// Variable statement
#[derive(Debug, Clone)]
pub struct VariableStmt {
    pub declaration: VariableDecl,
}

/// Function statement
#[derive(Debug, Clone)]
pub struct FunctionStmt {
    pub declaration: FunctionDecl,
}

impl fmt::Display for File {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "File {{")?;
        if let Some(ref package) = self.package {
            writeln!(f, "  Package: {}.{}", package.path.join("."), package.name)?;
        }
        for import in &self.imports {
            writeln!(f, "  Import: {}", import.path.join("."))?;
        }
        for decl in &self.declarations {
            writeln!(f, "  {:?}", decl)?;
        }
        write!(f, "}}")
    }
}